import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Represents a path, a sequence of vertices with some weight.
 * 
 * @param <V>
 *            The vertex inteface's implementing type
 */
public class Path<V extends Vertex<V>> implements Iterable<V> {

	private List<V> vertices;
	private int totalWeight;
	private int lastWeight;

	/**
	 * Constructs a new path by making a deep copy of an existing path, then
	 * appending a pair.
	 * 
	 * @param path
	 *            The path to copy
	 * @param pair
	 *            The pair to append
	 */
	public Path(Path<V> path, Pair<V> pair) {
		vertices = new ArrayList<V>();

		if (path != null) {
			totalWeight = path.getTotalWeight();
			vertices.addAll(path.getVertices());
		}

		lastWeight = pair.getWeight();
		totalWeight += lastWeight;
		vertices.add(pair.getVertex());
	}

	/**
	 * Constructs a path consisting of a single vertex (and thus, no weight).
	 * 
	 * @param vertex
	 *            The single Vertex
	 */
	public Path(V vertex) {
		this(null, new Pair<V>(vertex));
	}

	/**
	 * Determines if a vertex is in this path.
	 * 
	 * @param vertex
	 *            The vertex to search for
	 * @return true if the Vertex is in this Path, or false otherwise
	 */
	public boolean contains(Vertex<V> vertex) {
		return vertices.contains(vertex);
	}

	/**
	 * Returns the vertices in this path, separated by spaces.
	 */
	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();

		for (V vertex : vertices) {
			buffer.append(vertex);
			buffer.append(" ");
		}
		
		buffer.append('(');
		buffer.append(totalWeight);
		buffer.append(')');

		return buffer.toString();
	}

	/**
	 * Returns an iterator so this path can be traversed in for-each loops.
	 */
	@Override
	public Iterator<V> iterator() {
		return vertices.iterator();
	}

	/**
	 * Returns the last vertex
	 */
	public V getLastVertex() {
		return vertices.get(vertices.size() - 1);
	}

	/**
	 * Returns the list of vertices.
	 */
	public List<V> getVertices() {
		return vertices;
	}

	/**
	 * Returns the total weight of the edges in this path.
	 * 
	 * @return The total weight of the edges in this path
	 */
	public int getTotalWeight() {
		return totalWeight;
	}

	/**
	 * Returns the weight of last edge in this vertex.
	 * 
	 * @return The weight of last edge in this vertex
	 */
	public int getLastWeight() {
		return lastWeight;
	}
}
